#pragma once

#include <chrono>
#include <vector>

#include "armor_classifier.hpp"
#include "armor_detector.hpp"
#include "buff.hpp"
#include "detector.hpp"
#include "opencv2/opencv.hpp"

struct BuffDetectorParam {
  double binary_th;
  int se_erosion;    /* erosion in getStructuringElement */
  double ap_erosion; /* erosion in approxPolyDP */

  std::size_t contour_size_low_th;
  double rect_ratio_low_th;
  double rect_ratio_high_th;

  double contour_center_area_low_th;
  double contour_center_area_high_th;
  double rect_center_ratio_low_th;
  double rect_center_ratio_high_th;

  double hammer_area_low_th;
  double hammer_area_high_th;

  double armor_area_low_th;
  double armor_area_high_th;
};

class BuffDetector : private Detector<Armor, BuffDetectorParam> {
 private:
  Buff buff_;
  std::vector<std::vector<cv::Point>> contours_, contours_poly_;
  std::vector<cv::RotatedRect> rects_;      //矩形
  std::vector<cv::Point2f> circumference_;  //圆周
  cv::RotatedRect hammer_;                  //锤子
  float center_area_ = 0;                   //圆心面积

  /**
   * @brief 识别信息
   * 0000 0001 发现圆心
   * 0000 0010 发现锤子
   * 0000 0100 发现宝剑(未使用)
   * 0000 1000 发现装甲板
   * 0001 0000 发现目标
   * 
   */
  uint8_t info_ = 0;
  bool reseted_ = false;  //大能量机关是否失败过
  std::chrono::_V2::system_clock::time_point start_time_;

  std::chrono::milliseconds duration_armors_, duration_center_, duration_rects_;

  void InitDefaultParams(const std::string &path);

  /**
   * @brief Get the Time object (sesscond)
   *
   * @return double
   */
  double GetTime();

  void FindRects(const cv::Mat &frame);

  void MatchArmors();
  void MatchDirection();
  void MatchPredict();

  void VisualizeArmors(const cv::Mat &output, bool add_lable);

 public:
  BuffDetector();
  BuffDetector(const std::string &param_path, game::Team buff_team);
  ~BuffDetector();
  bool PrepareParams(const std::string &path);

  bool PrepareParams(const std::string &path);

  const std::vector<Armor> &Detect(const cv::Mat &frame);
  void Restart();

  void VisualizeResult(const cv::Mat &frame, int verbose);
};